<script setup lang="ts">
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { ref, onMounted } from 'vue'

const domEl = ref(null)

const demoList = ref([
  { fov: 75, position: [0, 0, 50], AxesLen: 10 },
  { fov: 75, position: [0, 0, 10], AxesLen: 5 },
  { fov: 75, position: [10, 10, 20], AxesLen: 20 },
  { fov: 75, position: [10, 10, 20], AxesLen: 20 },
  { fov: 75, position: [10, 10, 20], AxesLen: 20 },
  { fov: 75, position: [10, 10, 20], AxesLen: 20 },
  { fov: 75, position: [10, 10, 20], AxesLen: 20 },
])

class PopUpInfo extends HTMLElement {
  constructor() {
    super()

    const shadow = this.attachShadow({mode: 'open'})

    const wrapper = document.createElement('span')
    wrapper.setAttribute('class', 'wrapper')

    const icon = document.createElement('span')
    icon.setAttribute('class', 'icon')
    icon.setAttribute('tabindex', 0)

    const info = document.createElement('span')
    info.setAttribute('class', 'info')

    const text = this.getAttribute('data-text')
    info.innerHTML = text

    let imgUrl
    if(this.hasAttribute('img')) {
      imgUrl = this.getAttribute('img')
    } else {
      imgUrl = '/zm-docs/imgs/img_info.png'
    }

    const img = document.createElement('img')
    img.src = imgUrl
    icon.appendChild(img)

    const style = document.createElement('style')

    style.textContent = `
      .wrapper {
        position: relative;
      }

      .info {
        font-size: 0.8rem;
        min-width: 200px;
        text-wrap: nowrap;
        display: inline-block;
        border: 1px solid black;
        padding: 10px;
        background: white;
        border-radius: 10px;
        opacity: 0;
        transition: 0.6s all;
        position: absolute;
        bottom: 20px;
        left: 10px;
        z-index: 3;
      }

      img {
        width: 1.2rem;
      }

      .icon:hover + .info, .icon:focus + .info {
        opacity: 1;
      }
    `

    shadow.appendChild(style)
    shadow.appendChild(wrapper)
    wrapper.appendChild(icon)
    wrapper.appendChild(info)
  }
}

const infoJs = ref([
    `const points = [] <br/>
    points.push( new THREE.Vector3( - 10, 0, 0 ) )<br/>
    points.push( new THREE.Vector3( 0, 10, 0 ) )<br/>
    points.push( new THREE.Vector3( 20, 0, 0 ) )<br/>
    points.push( new THREE.Vector3( 40, 0, 0 ) )<br/>

    const geometry = new THREE.BufferGeometry().setFromPoints( points )<br/>
    const line = new THREE.Line( geometry, material )`,
    `const geometry = new THREE.BufferGeometry()<br/>

    const vertices = new Float32Array( [<br/>
      -1.0, -1.0,  1.0,<br/>
      1.0, -1.0,  1.0,<br/>
      1.0,  1.0,  1.0,<br/>

      1.0,  1.0,  1.0,<br/>
      -1.0,  1.0,  1.0,<br/>
      -1.0, -1.0,  1.0<br/>
    ] )<br/>

    geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) )<br/>
    const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } )`,
    `const vertices = new Float32Array( [<br/>
      -10, -0,  0,<br/>
      10, 0,  0,<br/>
      0,  10,  0,<br/>

      0,  0,  5,<br/>
      0,  10,  5,<br/>
      0, 0,  15<br/>
    ] )<br/>

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )<br/>

    let mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
      color: 0xff0000,
      side: THREE.DoubleSide
    }))`,
    `const vertices = new Float32Array( [<br/>
      -10, -0,  0,<br/>
      10, 0,  0,<br/>
      0,  10,  0,<br/>

      0,  0,  5,<br/>
      0,  10,  5,<br/>
      0, 0,  15<br/>
    ] )<br/>

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )<br/>

    let point = new THREE.Points(geometry, new THREE.PointsMaterial({<br/>
      color: 0xff0000,
      size: 3
    }))`,
    `const vertices = new Float32Array( [<br/>
      -10, -0,  0,<br/>
      10, 0,  0,<br/>
      0,  10,  0,<br/>

      0,  0,  5,<br/>
      0,  10,  5,<br/>
      0, 0,  15<br/>
    ] )<br/>

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )<br/>

    let line = new THREE.Line(geometry, new THREE.LineBasicMaterial({
      color: 0x00ffff
    }))`,
    `const vertices = new Float32Array( [<br/>
      -10, -0,  0,<br/>
      10, 0,  0,<br/>
      0,  10,  0,<br/>

      0,  0,  5,<br/>
      0,  10,  5,<br/>
      0, 0,  15<br/>
    ] )<br/>

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )<br/>

    const colors = new Float32Array([<br/>
      1, 0, 0, // 点1颜色<br/>
      0, 1, 0, // 点2颜色<br/>
      0, 0, 1, // 点3颜色<br/>

      1, 1, 0, // 点4颜色<br/>
      0, 1, 1, // 点5颜色<br/>
      1, 0, 1, // 点6颜色<br/>
    ])<br/>

    geometry.attributes.color = new THREE.BufferAttribute(colors, 3)<br/>

    let point = new THREE.Points(geometry, new THREE.PointsMaterial({
      vertexColors: true,
      size: 3
    }))`,
    `const vertices = new Float32Array( [<br/>
      -10, -0,  0,<br/>
      10, 0,  0,<br/>
      0,  10,  0,<br/>

      0,  0,  5,<br/>
      0,  10,  5,<br/>
      0, 0,  15<br/>
    ] )<br/>

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )<br/>

    const colors = new Float32Array([<br/>
      1, 0, 0, // 点1颜色<br/>
      0, 1, 0, // 点2颜色<br/>
      0, 0, 1, // 点3颜色<br/>

      1, 1, 0, // 点4颜色<br/>
      0, 1, 1, // 点5颜色<br/>
      1, 0, 1, // 点6颜色<br/>
    ])<br/>

    geometry.attributes.color = new THREE.BufferAttribute(colors, 3)<br/>

    let mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({<br/>
      vertexColors: true,<br/>
      side: THREE.DoubleSide
    }))`
])


const drawLine = (domEl, type = 1, positionList = [], AxesLen = 10) => {
  const renderer = new THREE.WebGLRenderer()
  renderer.setSize( domEl.clientWidth, domEl.clientHeight )
  domEl.appendChild( renderer.domElement )

  const camera = new THREE.PerspectiveCamera( 75, domEl.clientWidth / domEl.clientHeight, 1, 500 )
  camera.position.set( ...positionList )
  camera.lookAt( 0, 0, 0 )

  const scene = new THREE.Scene()

  const material = new THREE.LineBasicMaterial( { color: 0x0000ff } )

  if(type === 1) {
    const points = []
    points.push( new THREE.Vector3( - 10, 0, 0 ) )
    points.push( new THREE.Vector3( 0, 10, 0 ) )
    points.push( new THREE.Vector3( 20, 0, 0 ) )
    points.push( new THREE.Vector3( 40, 0, 0 ) )

    const geometry = new THREE.BufferGeometry().setFromPoints( points )
    const line = new THREE.Line( geometry, material )

    scene.add( line )
  }else if(type === 2) {
    const geometry = new THREE.BufferGeometry()

    const vertices = new Float32Array( [
      -1.0, -1.0,  1.0,
      1.0, -1.0,  1.0,
      1.0,  1.0,  1.0,

      1.0,  1.0,  1.0,
      -1.0,  1.0,  1.0,
      -1.0, -1.0,  1.0
    ] )

    geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) )
    // or geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    const material = new THREE.MeshBasicMaterial( { color: 0xff0000 } )


    const mesh = new THREE.Mesh( geometry, material )
    scene.add( mesh )
  }else if(type === 3) {
    const geometry = new THREE.BufferGeometry()

    const vertices = new Float32Array( [
      -10, -0,  0,
      10, 0,  0,
      0,  10,  0,

      0,  0,  5,
      0,  10,  5,
      0, 0,  15
    ] )

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    let mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
      color: 0xff0000,
      side: THREE.DoubleSide
    }))

    scene.add(mesh)
  }else if(type === 4) {
    const geometry = new THREE.BufferGeometry()

    const vertices = new Float32Array( [
      -10, -0,  0,
      10, 0,  0,
      0,  10,  0,

      0,  0,  5,
      0,  10,  5,
      0, 0,  15
    ] )

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    let point = new THREE.Points(geometry, new THREE.PointsMaterial({
      color: 0xff0000,
      size: 3
    }))

    scene.add(point)
  }else if(type === 5) {
    const geometry = new THREE.BufferGeometry()

    const vertices = new Float32Array( [
      -10, -0,  0,
      10, 0,  0,
      0,  10,  0,

      0,  0,  5,
      0,  10,  5,
      0, 0,  15
    ] )

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    let line = new THREE.Line(geometry, new THREE.LineBasicMaterial({
      color: 0x00ffff
    }))

    scene.add(line)
  }else if(type === 6) {
    const geometry = new THREE.BufferGeometry()
    const vertices = new Float32Array( [
      -10, -0,  0,
      10, 0,  0,
      0,  10,  0,

      0,  0,  5,
      0,  10,  5,
      0, 0,  15
    ] )

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    const colors = new Float32Array([
      1, 0, 0, // 点1颜色
      0, 1, 0, // 点2颜色
      0, 0, 1, // 点3颜色

      1, 1, 0, // 点4颜色
      0, 1, 1, // 点5颜色
      1, 0, 1, // 点6颜色
    ])

    geometry.attributes.color = new THREE.BufferAttribute(colors, 3)

    let point = new THREE.Points(geometry, new THREE.PointsMaterial({
      // color: 0xff0000,
      vertexColors: true,
      size: 3
    }))
    scene.add(point)
  }else if(type === 7) {
    const geometry = new THREE.BufferGeometry()

    const vertices = new Float32Array( [
      -10, -0,  0,
      10, 0,  0,
      0,  10,  0,

      0,  0,  5,
      0,  10,  5,
      0, 0,  15
    ] )

    geometry.attributes.position = new THREE.BufferAttribute( vertices, 3 )

    const colors = new Float32Array([
      1, 0, 0, // 点1颜色
      0, 1, 0, // 点2颜色
      0, 0, 1, // 点3颜色

      1, 1, 0, // 点4颜色
      0, 1, 1, // 点5颜色
      1, 0, 1, // 点6颜色
    ])

    geometry.attributes.color = new THREE.BufferAttribute(colors, 3)

    let mesh = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
      vertexColors: true,
      side: THREE.DoubleSide
    }))

    scene.add(mesh)
  }

  // 轨道
  const controls = new OrbitControls( camera, renderer.domElement )

  const axesHelper = new THREE.AxesHelper( AxesLen )
  scene.add( axesHelper )

  function animate() {
    requestAnimationFrame( animate )
    controls.update()
    renderer.render(scene, camera)
  }
  animate()

  window.addEventListener( 'resize', onWindowResize )
  function onWindowResize() {
    camera.aspect = domEl.clientWidth / domEl.clientHeight
    camera.updateProjectionMatrix()
    renderer.setSize( domEl.clientWidth, domEl.clientHeight )
  }
}

onMounted(() => {
  customElements.define('popup-info', PopUpInfo)

  demoList.value.forEach((item, index) => {
    drawLine(domEl.value[index], index+1, item.position, item.AxesLen)
  })
})

</script>

<template>
  <div class="domEl-class w-screen h-screen flex flex-wrap gap-2">
    <div v-for="(item, index) in demoList" :key="index">
      <div ref="domEl" style="height: calc(100% - 20px)"></div>
      <popup-info img="/zm-docs/imgs/img_info.png" :data-text="infoJs[index]"></popup-info>
    </div>
  </div>
</template>

<style scoped lang="scss">
.domEl-class {
  width: calc(100% - 1px);
  >div {
    width: calc(50% - 0.5rem/2);
    height: calc(50% - 0.5rem/2);
  }
}
</style>